import random
from XSY.Base import *
import math

class RandomVariable:
   '''the base class for a random variable of an arbitrary set S. The random variable is defined by a mapping: (s,r) where '''
   def sample(self):
      '''override method to sample a value of random variable'''
      raise Exception("RandomVariable::sample should be overrided!")

class RV_Triangular(RandomVariable):
   '''Random Variable having a triangular distribution density function. (low, hight, mode), defualt 
   low,hight = 0,1, and mode = (low+hight)/2'''
   def __init__(self, low, high, mode):
      self.low, self.high, self.mode = low, high, mode

   def sample(self):
      '''The ramdom sample v will be in low <= a <= hight, mode should be in [a,b]'''
      return random.triangular(self.low, self.high, self.mode) 

class RV_Exponential(RandomVariable):
   '''Exponential distribution.'''
   def __init__(self, mean):
      '''mean is a positive real that is the desired mean value'''
      if mean <= 0:
         raise Exception("mean should be greater than zero in RV_Exponential::__init__!")
      self.mean = mean

   def sample(self):
      ''' lambd is 1.0 divided by the desired mean. It should be nonzero. (The parameter would be called "lambda", but that is a reserved word in Python.) Returned values range from 0 to positive infinity if lambd is positive, and from negative infinity to 0 if lambd is negative.'''
      lambd = 1.0/self.mean
      return random.expovariate(lambd)

class DRV(RandomVariable):
   '''the discrete random variable. It has the probability function at self.table'''
   def __init__(self, table):
      '''The dictionary table provides the probability function: S -> [0,1], and guarantees that \Sum_{s \in S}: table(s) = 1.'''
      if(isinstance(table, dict)):
         cump = 0
         for k in table.keys():
            v = table[k]
            if v<0 or v > 1: raise Exception("Invalide Probability %s = %f"%(k,v))
            cump += v

      if len(table)>0 and math.fabs(cump-1.0)>0.0001:
         raise Exception("Cummlative value is not equal to 1 but %f"%cump)

      self.table = table

   def sample(self):
      '''same one instance from the table considering the probability'''
      r = random.random()
      if r<0 or r > 1: raise Exception("Invalide random number %f"%r)

      cump = 0
      for k in self.table.keys():
         v = self.table[k]
         if v<0 or v > 1: raise Exception("Invalide Probability %s = %f"%(k,v))
         cump += v
         if cump > r: return k
      
      return None # empty table

#def isnumeric(v):
#   '''check if v is integer or float'''
#   return isinstance(v, int) or isinstance(v, float) #type(1)==type(v) or type(1.1)==type(v)

